package strategy;

import java.io.BufferedReader;
import java.io.FileReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import java.util.StringTokenizer;

import main.U;
import mt.BaiduMT;
import mt.GoogleMT;
import mt.YoudaoMT;
import edu.cmu.meteor.scorer.MeteorConfiguration;
import edu.cmu.meteor.scorer.MeteorScorer;
import edu.cmu.meteor.util.Constants;

public class FeatureCalc {

	static HashMap<String, Double> googleSentLmMap = new HashMap<String, Double>();
	static HashMap<String, Double> baiduSentLmMap = new HashMap<String, Double>();
	static HashMap<String, Double> youdaoSentLmMap = new HashMap<String, Double>();
	
	static MeteorScorer scorer = null;
	static {
		initSentLmMap("./data/mtRes/google.txt", "./data/mtRes/gLogP.txt");
		initSentLmMap("./data/mtRes/baidu.txt", "./data/mtRes/bLogP.txt");
		initSentLmMap("./data/mtRes/youdao.txt", "./data/mtRes/yLogP.txt");
		
		MeteorConfiguration config = new MeteorConfiguration();
		config.setLanguage("en");
		config.setNormalization(Constants.NORMALIZE_KEEP_PUNCT);
		/*try {
			config.setParaFileURL(new URL("file:///D:/paraphrase-en.gz"));
		} catch (Exception e) {
			e.printStackTrace();
		}*/
		scorer = new MeteorScorer(config);
		
	}
	
	public static void initSentLmMap(String sentFile, String logPFile) {
		try {
			BufferedReader inSent = new BufferedReader(new FileReader(sentFile));
			BufferedReader inLogP = new BufferedReader(new FileReader(logPFile));
			String lineSent = null;
			String lineLogP = null;
			while ((lineSent = inSent.readLine()) != null) {
				lineLogP = inLogP.readLine();
				googleSentLmMap.put(lineSent, Double.parseDouble(lineLogP));
			}
			inSent.close();
			inLogP.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 
	 * @param translations, 对于一句话的翻译结果，{google=xxx, baidu=yyy, youdao=zzz}
	 * @return 对于一句话的三家的翻译结果的BLEU属性，
	 *         eg, {google=0.2, baidu=0.3, youdao=0.4}
	 */
	public static HashMap<String, Double> getLmLogP(HashMap<String, String> translations) throws Exception {
		String google = translations.get(GoogleMT.label);
		String baidu = translations.get(BaiduMT.label);
		String youdao = translations.get(YoudaoMT.label);
		
		//从nc116 lm server线上获取，慢。
		double googleScore = getLmLogPSingle(google);
		double baiduScore = getLmLogPSingle(baidu);
		double youdaoScore = getLmLogPSingle(youdao);
		
		//从本地获取，快。
		//double googleScore = getLmLogPSingleFast(google, GoogleMT.label);
		//double baiduScore = getLmLogPSingleFast(baidu, BaiduMT.label);
		//double youdaoScore = getLmLogPSingleFast(youdao, YoudaoMT.label);
		
		HashMap<String, Double> res = new HashMap<String, Double>();
		res.put(GoogleMT.label, googleScore);
		res.put(BaiduMT.label, baiduScore);
		res.put(YoudaoMT.label, youdaoScore);
		
		return res;
	}
	
	public static double getLmLogPSingleFast(String sentence, String label) throws Exception {
		if (label.equals(GoogleMT.label)) {
			if( googleSentLmMap.containsKey(sentence)) {
				return googleSentLmMap.get(sentence);
			} else {
				return getLmLogPSingle(sentence);
			}
		} else if ( label.equals(BaiduMT.label)) {
			if( baiduSentLmMap.containsKey(sentence)) {
				return baiduSentLmMap.get(sentence);
			} else {
				return getLmLogPSingle(sentence);
			}
		} else if ( label.equals(YoudaoMT.label)) {
			if (youdaoSentLmMap.containsKey(sentence)) {
				return youdaoSentLmMap.get(sentence);
			} else {
				return getLmLogPSingle(sentence);
			}
		} else {
			return getLmLogPSingle(sentence);
		}
	}
	
	
	
	public static double getLmLogPSingle(String sentence) throws Exception {

		int length =sentence.split(" ").length;
		sentence = U.preprocessStrForHttptransmition(sentence);
		String doubleString = U
				.getHTMLSource("http://nc116x.corp.youdao.com:50429/bm/bridge?s="
						+ sentence);
		System.out.println("doubleString=" + doubleString);
		double result =-1;
		try {
			result =Double.parseDouble(doubleString) / length;
		}catch (Exception e) {
			return -1;
		}
		return result;
		//return 1;
	}
	
	public static HashMap<String, Double> getMETEORWithRef(HashMap<String, String> translations, ArrayList<String> refList) {
		
		
		String google = translations.get(GoogleMT.label);
		String baidu = translations.get(BaiduMT.label);
		String youdao = translations.get(YoudaoMT.label);
		
		
		double googleScore = scorer.getMeteorStats(google, refList).score;

		double baiduScore = scorer.getMeteorStats(baidu, refList).score;

		double youdaoScore = scorer.getMeteorStats(youdao, refList).score;
		
		System.out.println();
		System.out.println(refList.get(0) + "\n");
		System.out.println("scores = " + googleScore + "\t" + baiduScore + "\t" + youdaoScore);
		System.out.println("google = " + google);
		System.out.println("baidu  = " + baidu);
		System.out.println("youdao = " + youdao);
		System.out.println();
		
		HashMap<String, Double> res = new HashMap<String, Double>();
		res.put(GoogleMT.label, googleScore);
		res.put(BaiduMT.label, baiduScore);
		res.put(YoudaoMT.label, youdaoScore);

		return res;
	}
	
	
	public static HashMap<String, Double> getMETEOR(HashMap<String, String> translations) {

		String google = translations.get(GoogleMT.label);
		String baidu = translations.get(BaiduMT.label);
		String youdao = translations.get(YoudaoMT.label);
		
		ArrayList<String> googleRefs = new ArrayList<String>();
		googleRefs.add(baidu);
		googleRefs.add(youdao);
		double googleScore = scorer.getMeteorStats(google, googleRefs).score;
		
		ArrayList<String> baiduRefs = new ArrayList<String>();
		baiduRefs.add(google);
		baiduRefs.add(youdao);
		double baiduScore = scorer.getMeteorStats(baidu, baiduRefs).score;
		
		ArrayList<String> youdaoRefs = new ArrayList<String>();
		youdaoRefs.add(google);
		youdaoRefs.add(baidu);
		double youdaoScore = scorer.getMeteorStats(youdao, youdaoRefs).score;
		
		//System.out.println("METEOR scores = " + googleScore + "\t" + baiduScore + "\t" + youdaoScore);
		
		
		HashMap<String, Double> res = new HashMap<String, Double>();
		res.put(GoogleMT.label, googleScore);
		res.put(BaiduMT.label, baiduScore);
		res.put(YoudaoMT.label, youdaoScore);

		return res;
	}
	
	
	/**
	 * 
	 * @param translations, 对于一句话的翻译结果，{google=xxx, baidu=yyy, youdao=zzz}
	 * @return 对于一句话的三家的翻译结果的BLEU属性，
	 *         eg, {google=0.2, baidu=0.3, youdao=0.4}
	 */
	public static HashMap<String, Double> getBLEU(HashMap<String, String> translations) {
		String google = translations.get(GoogleMT.label);
		String baidu = translations.get(BaiduMT.label);
		String youdao = translations.get(YoudaoMT.label);
		
		double googleScore = getBleuSbp(google, baidu, youdao);
		double baiduScore = getBleuSbp( baidu, google,youdao);
		double youdaoScore = getBleuSbp(youdao, google, baidu);
		//System.out.println("google=" + google);
		//System.out.println("baidu=" + baidu);
		//System.out.println("youdao=" + youdao);
		//System.out.println("BLEU g, b, y = " + googleScore + "\t" + baiduScore + "\t" + youdaoScore);
		
		HashMap<String, Double> res = new HashMap<String, Double>();
		res.put(GoogleMT.label, googleScore);
		res.put(BaiduMT.label, baiduScore);
		res.put(YoudaoMT.label, youdaoScore);

		return res;
	}
	
	//helper
	//default order = 4
	static double getBleuSbp(String tst, String ref1, String ref2) {
		double avgLogP = 0;
		for (int i = 1; i <= 4; i++) {
			HashMap<String, Integer> map0 = getNgramMap(tst, i);
			HashMap<String, Integer> map1 = getNgramMap(ref1, i);
			HashMap<String, Integer> map2 = getNgramMap(ref2, i);
			double p = getP(map0, map1, map2);
			avgLogP += Math.log(p) / 4;
		}
		double bleu = Math.exp(avgLogP);
		double bp = getBp(tst, 30);
		double bleuSbp = bleu * bp;
		return bleuSbp;
	}
	
	//helper
	static double getBp(String tst, double r) {
		String[] splits = tst.split("\\s+");
		double c = splits.length;
		double expFactor = c > r ? 0 : 1 - r / c;
		return Math.exp(expFactor);
	}
	
	//helper
	static double getP(HashMap<String, Integer> tstMap, HashMap<String, Integer> ref1Map, HashMap<String, Integer> ref2Map) {
		HashMap<String, Integer> tstClipMap = new HashMap<String, Integer>();
		Set<String> iterSet = tstMap.keySet();
		for(String token : iterSet) {
			int tstCount = tstMap.get(token);
			
			int count1 = ref1Map.containsKey(token) ? ref1Map.get(token) : 0;
			int count2 = ref2Map.containsKey(token) ? ref2Map.get(token) : 0;
			
			int maxRef = count1 > count2 ? count1 : count2;
			int tstClipCount = tstCount < maxRef ? tstCount : maxRef;
			tstClipMap.put(token, tstClipCount);
		}
		int sigmaCount = 0;
		int sigmaClipCount = 0;
		for(String token : iterSet) {

			sigmaCount += tstMap.get(token);
			sigmaClipCount += tstClipMap.get(token);
		}
		//System.out.println(sigmaCount);
		//System.out.println(sigmaClipCount);
		double p = (0.0 + sigmaClipCount) / sigmaCount;
		return p;
	}
	
	//helper
	static HashMap<String, Integer> getNgramMap(String sent, int n) {
		HashMap<String, Integer> ngramMap = new HashMap<String, Integer>();
		
		ngramMap.put("<s>", 1);//每个order先放一个<s>进去，防止到高阶（比如4）出现匹配为0时使得BLEU-SBP为0。
		
		StringTokenizer stk = new StringTokenizer(sent);
		
		if( stk.countTokens() < n) {
			ngramMap.put(sent, 1);
			return ngramMap;
		}
		
		ArrayList<String> tokenList = new ArrayList<String>();
		while(stk.hasMoreTokens()) {
			tokenList.add(stk.nextToken());
		}
		
		for( int i = 0; i <= tokenList.size() - n; i++) {
			String ngram = "";
			for( int j = 0; j < n; j++) {
					ngram += tokenList.get(i + j) + "_";
					//System.out.println("ngram=" + ngram);
			}
			
			if( !ngramMap.containsKey(ngram)) {
				ngramMap.put(ngram, 1);
			} else {
				ngramMap.put(ngram, ngramMap.get(ngram) + 1);
			}
		}
		return ngramMap;
	}
	
	/**
	 * 
	 * @param translations, 对于一句话的翻译结果，{google=xxx, baidu=yyy, youdao=zzz}
	 * @return 对于一句话的三家的翻译结果的editDistance属性，
	 *         eg, {google=5.0, baidu=3.0, youdao=4.0}
	 */
	public static HashMap<String, Double> getEditDist(
			HashMap<String, String> translations) throws Exception {

		String google = translations.get(GoogleMT.label);
		String baidu = translations.get(BaiduMT.label);
		String youdao = translations.get(YoudaoMT.label);

		HashMap<String, Double> res = new HashMap<String, Double>();

		double gb = getEDScore(google, baidu);
		double gy = getEDScore(google, youdao);
		double by = getEDScore(youdao, baidu);

		res.put(GoogleMT.label, (gb + gy) / 2);
		res.put(BaiduMT.label, (gb + by) / 2);
		res.put(YoudaoMT.label, (gy + by) / 2);

		return res;

	}

	//helper
	static int getEDScore(String s1, String s2) {
		String[] splits1 = s1.split(" +");
		ArrayList<String> list1 = new ArrayList<String>();
		for (int i = 0; i < splits1.length; i++) {
			if (splits1[i].matches("[0-9a-zA-Z]+")) {
				list1.add(splits1[i]);
			}
		}
		String[] splits2 = s2.split(" +");
		ArrayList<String> list2 = new ArrayList<String>();
		for (int i = 0; i < splits2.length; i++) {
			if (splits2[i].matches("[0-9a-zA-Z]+")) {
				list2.add(splits2[i]);
			}
		}

		int[][] matrix = new int[list1.size() + 1][list2.size() + 1];
		for (int i = 0; i < list1.size() + 1; i++) {
			matrix[i][0] = 0;
		}
		for (int j = 0; j < list2.size() + 1; j++) {
			matrix[0][j] = 0;
		}
		int i = 0;
		int j = 0;
		for (i = 1; i < list1.size() + 1; i++) {
			for (j = 1; j < list2.size() + 1; j++) {
				if (list1.get(i - 1).equals(list2.get(j - 1))) {// i,j is the
																// tag on
																// matrix, in
																// splits1,splits2
																// they should
																// be i-1, j-1
					matrix[i][j] = getMin(matrix[i - 1][j], matrix[i][j - 1],
							matrix[i - 1][j - 1]);
				} else {
					matrix[i][j] = getMin(matrix[i - 1][j], matrix[i][j - 1],
							matrix[i - 1][j - 1]) + 1;
				}
			}
		}

		// output the matrix for debugging
		// for( int x = 0; x < splits1.length + 1; x++) {
		// for( int y = 0; y < splits2.length + 1; y++) {
		// System.out.print(matrix[x][y] + "\t");
		// }
		// System.out.println();
		// }

		return matrix[list1.size()][list2.size()];
	}

	//helper
	static int getMin(int a, int b, int c) {
		int mi;
		mi = a;
		if (b < mi) {
			mi = b;
		}
		if (c < mi) {
			mi = c;
		}
		return mi;
	}
	
	
	public static void main(String[] args) throws Exception {
		//System.out.println(getLmLogPSingle("Democracy is so accomplished gradually !"));
	}
}
